import { _decorator, Camera, Component, director, EventTouch, find, geometry, Input, input, instantiate, Material, Mesh, MeshRenderer, Node, screen, v2, v3, Vec2 } from 'cc';
import { tgxUIAlert, tgxUIMgr } from '../../core_tgx/tgx';
import { EasyController, EasyControllerEvent } from '../../core_tgx/easy_controller/EasyController';
import { GomokuGameEvent, GomokuGameMgr } from '../scripts/GomokuGameMgr';
import { UserMgr } from '../../module_basic/scripts/UserMgr';
import { SceneUtil } from '../../core_tgx/base/SceneUtils';
import { GameMode } from '../../module_basic/scripts/GameMgr';
import { GomokuAI } from './GomokuAI';
const { ccclass, property } = _decorator;

const tmpV2 = v2();
const tmpRay = new geometry.Ray();

const gridPlane = new geometry.Plane(0, 1, 0, -0.2);

@ccclass('GomokuGamePlay')
export class GomokuGamePlay extends Component {

    private _piecePool = [];
    getFromPool(v: number) {
        let node: Node = this._piecePool.pop();
        if (!node) {
            node = instantiate(this.white);
        }
        let meshRenderer = node.getComponent(MeshRenderer);
        let mat = this.matBlack;
        if (v == 2) {
            mat = this.matWhite;
        }
        meshRenderer.setMaterial(mat, 0);
        return node;
    }

    putToPool(node: Node) {
        if (!node) {
            return;
        }
        node.removeFromParent();
        this._piecePool.push(node);
    }

    @property(Node)
    white: Node;

    @property(Node)
    black: Node;

    @property(Node)
    pieceRoot: Node;

    @property(Material)
    matWhite: Material;

    @property(Material)
    matWhiteHighlight: Material;

    @property(Material)
    matBlack: Material;

    @property(Material)
    matBlackHighlight: Material;


    private _touchStartTime = 0;
    private _currentSide = 'black';
    private _touchStartPoint = v2();

    start() {
        
        this.putToPool(this.white);
        this.putToPool(this.black);

        EasyController.on(EasyControllerEvent.SCREEN_TOUCH_START, this.onTouchStart, this);
        EasyController.on(EasyControllerEvent.SCREEN_TOUCH_END, this.onTouchEnd, this);

        director.getScene().on(GomokuGameEvent.PLACE_PIECE, this.onPlacePiece, this);
        director.getScene().on(GomokuGameEvent.GAME_BEGIN, this.onGameBegin, this);
        director.getScene().on(GomokuGameEvent.GAME_OVER, this.onGameOver, this);

        this.initBoard();

        if(GomokuGameMgr.inst.gameMode == GameMode.AI){
            this.node.addComponent(GomokuAI);
        }
    }

    protected onDestroy(): void {
        EasyController.off(EasyControllerEvent.SCREEN_TOUCH_START, this.onTouchStart, this);
        EasyController.off(EasyControllerEvent.SCREEN_TOUCH_END, this.onTouchEnd, this);
    }

    async onGameBegin() {
        await SceneUtil.reloadScene();
        this.scheduleOnce(() => {
            tgxUIAlert.show("游戏开始！");
        }, 0.1);
    }

    async onGameOver(data: { winner: string, reason: number }) {
        if (GomokuGameMgr.inst.isPlayer) {
            if (data.reason == 1) {
                tgxUIAlert.show('对手认输，你赢了！').onClick(() => {
                    GomokuGameMgr.inst.backToLobby();
                });
            }
            else {
                if (data.winner == UserMgr.inst.userId) {
                    tgxUIAlert.show('你赢了！').onClick(() => {
                        GomokuGameMgr.inst.backToLobby();
                    });;
                }
                else {
                    tgxUIAlert.show('你输了！').onClick(() => {
                        GomokuGameMgr.inst.backToLobby();
                    });;
                }
            }
        }
        else {
            let userInfo = await UserMgr.inst.rpc_GetUserInfo(data.winner);
            if (data.reason == 1) {
                tgxUIAlert.show('对手认输，玩家[' + userInfo.name + '] 获胜！').onClick(() => {
                    GomokuGameMgr.inst.backToLobby();
                });
            }
            else {
                tgxUIAlert.show('玩家[' + userInfo.name + '] 获胜！').onClick(() => {
                    GomokuGameMgr.inst.backToLobby();
                });
            }
        }

    }

    initBoard() {
        this.cleanBoard();
        let sizeInGrid = GomokuGameMgr.inst.boardMgr.sizeInGrid;
        for (let i = 0; i < sizeInGrid; ++i) {
            for (let j = 0; j < sizeInGrid; ++j) {
                let v = GomokuGameMgr.inst.boardMgr.getGridData(i, j);
                if (v) {
                    this.placePiece(i, j, v);
                }
            }
        }

    }

    onTouchStart(evt: EventTouch) {
        this._touchStartTime = Date.now();
        this._touchStartPoint.set(evt.touch.getLocation());
    }

    async onTouchEnd(evt: EventTouch) {
        let dx = this._touchStartPoint.x - evt.touch.getLocationX();
        let dy = this._touchStartPoint.y - evt.touch.getLocationY();

        /**
         * @en if touch point has been moved or held more than 200 ms, ignore this to avoid mis-operation.
         * @zh 如果触点有移动，或者按下时间超过200ms 则不走着子流程，防止误触
        **/
        if (dx * dx + dy * dy > 1 || Date.now() - this._touchStartTime > 200) {
            return;
        }
        if (!GomokuGameMgr.inst.isMyTurn) {
            return;
        }

        evt.getLocation(tmpV2);
        console.log(tmpV2);
        let camera = find('Main Camera').getComponent(Camera);
        camera.screenPointToRay(tmpV2.x, tmpV2.y, tmpRay);

        let dist = geometry.intersect.rayPlane(tmpRay, gridPlane);

        let point = v3();
        tmpRay.computeHit(point, dist);


        //let pos = GomokuGridMgr.inst.getNearestGridCenter(point.x, point.z);
        let grid = GomokuGameMgr.inst.boardMgr.posToGrid(point.x, point.z);
        let v = GomokuGameMgr.inst.boardMgr.getGridData(grid.x, grid.y);
        if (v) {
            //tgxUIAlert.show('此处已有子!');
            return;
        }

        let placeV = GomokuGameMgr.inst.selfPlayer.color == 'black' ? 1 : 2;

        let placer = this.getFromPool(placeV);

        let pos = GomokuGameMgr.inst.boardMgr.gridToPos(grid.x, grid.y);
        placer.setPosition(pos.x, 0, pos.y);

        let ret = await GomokuGameMgr.inst.rpc_PlacePiece(grid.x, grid.y);
        if (!ret.isSucc) {
            tgxUIAlert.show(ret.err.message);
        }
        this.putToPool(placer);
    }

    private _lastNewPiece: Node = null;
    private _lastNewPieceValue = 0;
    onPlacePiece(data: { gridX: number, gridY: number }) {
        let v = GomokuGameMgr.inst.boardMgr.getGridData(data.gridX, data.gridY);
        let newPiece = this.placePiece(data.gridX, data.gridY, v);

        if (this._lastNewPiece) {
            let normalMat = this._lastNewPieceValue == 1 ? this.matBlack : this.matWhite;
            this._lastNewPiece.getComponent(MeshRenderer).setMaterial(normalMat, 0);
        }

        let highlightMat = v == 1 ? this.matBlackHighlight : this.matWhiteHighlight;
        newPiece.getComponent(MeshRenderer).setMaterial(highlightMat, 0);
        this._lastNewPiece = newPiece;
        this._lastNewPieceValue = v;
    }

    cleanBoard() {
        for (let i = this.pieceRoot.children.length - 1; i >= 0; --i) {
            this.putToPool(this.pieceRoot.children[i]);
        }
        this._lastNewPiece = null;
    }

    placePiece(gridX: number, gridY: number, v: number) {
        let node = this.getFromPool(v);
        let pos = GomokuGameMgr.inst.boardMgr.gridToPos(gridX, gridY);
        node.setPosition(pos.x, 0, pos.y);
        this.pieceRoot.addChild(node);
        return node;
    }

    randomLayPieceTest() {
        for (let i = 0; i < 64; ++i) {
            for (let j = 0; j < 64; ++j) {
                let v = Math.floor(Math.random() * 3);
                GomokuGameMgr.inst.boardMgr.setGrid(i, j, v);
            }
        }

        for (let i = 0; i < 64; ++i) {
            for (let j = 0; j < 64; ++j) {
                let pos = GomokuGameMgr.inst.boardMgr.gridToPos(i, j);
                let v = GomokuGameMgr.inst.boardMgr.getGridData(i, j);
                console.log(v);
                if (v != 0) {
                    let prefab = this.black;
                    if (v == 2) {
                        prefab = this.white;
                    }
                    let node: Node = instantiate(prefab);
                    node.setPosition(pos.x, 0, pos.y);
                    this.node.addChild(node);
                }
            }
        }
    }

    update(deltaTime: number) {

    }
}


